#include "napi/native_api.h"
#include "infones_adapter.h"
#include <cstdio>

// 初始化NES模拟器
static napi_value InitNES(napi_env env, napi_callback_info info)
{
    bool result = InfoNES_Adapter_Init();
    napi_value ret;
    napi_get_boolean(env, result, &ret);
    return ret;
}

// 加载ROM
static napi_value LoadROM(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 1) {
        napi_value ret;
        napi_get_boolean(env, false, &ret);
        return ret;
    }

    // 获取ArrayBuffer
    napi_valuetype valuetype;
    napi_typeof(env, args[0], &valuetype);
    if (valuetype != napi_object) {
        napi_value ret;
        napi_get_boolean(env, false, &ret);
        return ret;
    }

    uint8_t* data = nullptr;
    size_t size = 0;
    napi_get_arraybuffer_info(env, args[0], (void**)&data, &size);

    bool result = InfoNES_Adapter_LoadROM(data, size);
    napi_value ret;
    napi_get_boolean(env, result, &ret);
    return ret;
}

// 运行一帧
static napi_value RunFrame(napi_env env, napi_callback_info info)
{
    InfoNES_Adapter_RunFrame();
    napi_value ret;
    napi_get_undefined(env, &ret);
    return ret;
}

// 设置控制器状态
static napi_value SetController(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value args[2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 2) {
        napi_value ret;
        napi_get_undefined(env, &ret);
        return ret;
    }

    int32_t controller;
    napi_get_value_int32(env, args[0], &controller);

    int32_t state;
    napi_get_value_int32(env, args[1], &state);

    InfoNES_Adapter_SetControllerState(controller, (uint8_t)state);
    
    napi_value ret;
    napi_get_undefined(env, &ret);
    return ret;
}

// 获取屏幕缓冲区
static napi_value GetScreenBuffer(napi_env env, napi_callback_info info)
{
    uint16_t* buffer = InfoNES_Adapter_GetScreenBuffer();
    if (buffer == nullptr) {
        napi_value ret;
        napi_get_null(env, &ret);
        return ret;
    }
    
    size_t size = 256 * 240 * sizeof(uint16_t); // NES标准分辨率
    
    napi_value array_buffer;
    napi_create_arraybuffer(env, size, (void**)&buffer, &array_buffer);
    
    return array_buffer;
}

// 检查是否运行中
static napi_value IsRunning(napi_env env, napi_callback_info info)
{
    bool running = InfoNES_Adapter_IsRunning();
    napi_value ret;
    napi_get_boolean(env, running, &ret);
    return ret;
}

// 暂停/恢复
static napi_value Pause(napi_env env, napi_callback_info info)
{
    InfoNES_Adapter_Pause();
    napi_value ret;
    napi_get_undefined(env, &ret);
    return ret;
}

static napi_value Resume(napi_env env, napi_callback_info info)
{
    InfoNES_Adapter_Resume();
    napi_value ret;
    napi_get_undefined(env, &ret);
    return ret;
}

// 重置
static napi_value Reset(napi_env env, napi_callback_info info)
{
    InfoNES_Adapter_Reset();
    napi_value ret;
    napi_get_undefined(env, &ret);
    return ret;
}

// 设置Native Window
static napi_value SetNativeWindow(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 1) {
        napi_value ret;
        napi_get_undefined(env, &ret);
        return ret;
    }

    // 获取Native Window指针
    void* window = nullptr;
    napi_status status = napi_get_value_external(env, args[0], &window);
    
    if (status != napi_ok || window == nullptr) {
        // 如果获取外部值失败，尝试获取字符串（surfaceId）
        char surfaceId[256];
        size_t result;
        status = napi_get_value_string_utf8(env, args[0], surfaceId, sizeof(surfaceId), &result);
        
        if (status == napi_ok) {
            // 暂时使用surfaceId作为标识符
            // 在实际实现中，需要根据surfaceId获取真正的Native Window
            printf("Received surfaceId: %s\n", surfaceId);
            // 这里可以添加从surfaceId获取Native Window的逻辑
        }
    } else {
        InfoNES_Adapter_SetNativeWindow(window);
    }
    
    napi_value ret;
    napi_get_undefined(env, &ret);
    return ret;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "initNES", nullptr, InitNES, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "loadROM", nullptr, LoadROM, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "runFrame", nullptr, RunFrame, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "setController", nullptr, SetController, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getScreenBuffer", nullptr, GetScreenBuffer, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "isRunning", nullptr, IsRunning, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "pause", nullptr, Pause, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "resume", nullptr, Resume, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "reset", nullptr, Reset, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "setNativeWindow", nullptr, SetNativeWindow, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module infonesModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "infones",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&infonesModule);
}
